How to set the center of the actor to be the same as the center of mass of the body - libgdx

Here is a star-shaped body created with Physics Body Editor with the center of mass in the middle:
val bodyEditorLoader by lazy { BodyEditorLoader(Gdx.files.internal("phisics/GameBox2D.json")) }
val starBody = createStar()
private fun createStar(): Body {
val bodyDef = BodyDef().apply {
type = BodyDef.BodyType.DynamicBody
position.set(
mainLayoutUtil.getSizeW(700f),
mainLayoutUtil.getSizeH(350f),
)
}
val body = WorldUtil.world.createBody(bodyDef)
val fixtureDef = FixtureDef().apply {
restitution = 0.7f
density = 1f
}
bodyEditorLoader.attachFixture(body, "Star", fixtureDef, 10f)
return body
"rigidBodies": [
{
"name": "Star",
"imagePath": "../star.png",
"origin": {
"x": 0.5,
"y": 0.5,
},
}
...
]
The image that needs to display the body data:
private val starImage = Image(SpriteManager.GameRegion.STAR.region)
Image rendering method according to body data:
override fun render(delta: Float) {
super.render(delta)
WorldUtil.update(delta)
WorldUtil.debug(viewport.camera.combined)
renderStar()
}
private fun renderStar() {
starImage.apply {
x = starBody.???
y = starBody.???
setOrigin(starBody.???)
rotation = Math.toDegrees(starBody.???).toFloat()
}
}
What body data should I use to correctly render the image according to the body data?

Create a variable into which the Vector2 will be written:
var starCenter = Vector2()
In the body creation method, write the center of mass to the already created variable:
private fun createStar(): Body {
val center = bodyEditorLoader.getOrigin("Star", 10F)
starCenter = center
return body
}
Replace the image data with the following body data to render the image correctly:
private fun renderStar() {
starImage.apply {
x = starBody.position.x - starCenter.x
y = starBody.position.y - starCenter.y
setOrigin(starCenter.x, starCenter.y)
rotation = Math.toDegrees(starBody.angle.toDouble()).toFloat()
}
}

Related

How do I change an UI/Image when there's 2 gameobjects with the same name?

I'm developing an application for the hololens that generates multiple canvases with a panel with UI/Image elements. I have 1 JSON string:
{
"PC_Station":[
{
"PLC_0":{
"DB1":{
"test123":0
},
"STOP":false,
"Frap":false,
"START":false,
"Start_1":false,
"Stop_1":false,
"Led1":true,
"Led2":false,
"Led3":true,
"Counter":4002,
"Sliderval":0
}
},
{
"PLC_1":{
"DB1":{
"test123":55
},
"STOP":false,
"START":false,
"Start_1":false,
"Stop_1":false,
"Led1":true,
"Led2":false,
"Led3":true,
"Counter":4002,
"Sliderval":0
}
}
]
}
This JSON string has 2 JSON objects inside a JSON array called PLC_1 and PLC_0. PLC_1 has the same variables as PLC_0.
I've made the following function that appends the JSON and changes the color of the UI/Image objects:
IEnumerator updateTags()
{
string json = "{\"PC_Station\": [{\"PLC_1\": {\"DB1\": {\"test123\": 30}, \"STOP\": false, \"START\": true, \"Start_1\": false, \"Stop_1\": true, \"Led1\": false, \"Led2\": false, \"Led3\": false, \"Counter\": 3880, \"Sliderval\": 60}}]}";
string json1 = "{\"PC_Station\": [{\"PLC_0\": {\"DB1\": {\"test123\": 0}, \"STOP\": false,\"Frap\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}},{\"PLC_1\": {\"DB1\": {\"test123\": 55}, \"STOP\": false, \"START\": false, \"Start_1\": false, \"Stop_1\": false, \"Led1\": true, \"Led2\": false, \"Led3\": true, \"Counter\": 4002, \"Sliderval\": 0}}]}";
var data = JToken.Parse(json1);
while (true)
{
foreach (var value in data)
{
foreach(JArray arr in value)
{
for (int i = 0; i < arr.Count; i++)
{
foreach (var item in arr[i])
{
var itemproperties = item.Parent;
foreach (JToken token in itemproperties)
{
var prop = token as JProperty;
var plc = (JObject)prop.Value;
foreach (KeyValuePair<string, JToken> val in plc)
{
if(val.Value is JObject)
{
JObject nestedobj = (JObject)val.Value;
foreach (JProperty nestedvariables in nestedobj.Properties())
{
string varkey = nestedvariables.Name;
string varvalue = nestedvariables.Value.ToString();
GameObject test = GameObject.Find(varkey+"value");
test.GetComponent<Text>().text = varvalue;
}
}
else
{
for(int v = 0; v < abc.Count; v++)
{
Debug.Log(v);
foreach(KeyValuePair<string, string> variab in abc[v])
{
string varkey = val.Key;
string varvalue = val.Value.ToString();
GameObject test = GameObject.Find(varkey);
if(varvalue == "True")
{
test.GetComponent<Image>().color = Color.green;
}
if(varvalue == "False")
{
test.GetComponent<Image>().color = Color.red;
}
if(varvalue != "True" && varvalue != "False")
{
GameObject text = GameObject.Find(varkey + "value");
text.GetComponent<Text>().text = varvalue;
}
}
}
}
}
}
}
}
}
}
yield return new WaitForSeconds(0.5f);
}
}
When I run the programme, it looks like this:
As you can see, the function properly adds color to the UI/Images.
Now, for my question:
How can I make it so that the UI/Images on both canvases get filled with color despite having the same name?
There are no obvious solutions as GameObject referenes do not serialize easily, you couls reference objects by their position in the current branch of the tree (transform.GetSiblingIndex()) but that will not work if you move stuff around.
You could also just rename your objects.
Managed to fix it by using transform.find. I used it to find items in the hierarchy.
The code now functions like I want it to.
First I make a new gameobject:
public GameObject upd4;
Then I use it in my code as follows:
upd4 = transform.Find("Canvas" + i + "/Panel/" + plcvvobj.Key + "/" + plcvvobj.Key + "value").gameObject;
BTW, my hierarchy is as follows:

How to create notification badge in tableview

How to make a notification badge on the table view?
If there is new data it will display the badge on the table view, and if there is new data again, the badge will automatically be added.
I can strongly recommend you use the following Framework: swift-badge
use_frameworks!
target 'Your target name'
pod 'BadgeSwift', '~> 4.0'
Easy to use:
let badge = BadgeSwift()
view.addSubview(badge)
// Position the badge ...
Customization:
// Text
badge.text = "2"
// Insets
badge.insets = CGSize(width: 12, height: 12)
// Font
badge.font = UIFont.preferredFont(forTextStyle: UIFontTextStyle.body)
// Text color
badge.textColor = UIColor.yellow
// Badge color
badge.badgeColor = UIColor.black
// Shadow
badge.shadowOpacityBadge = 0.5
badge.shadowOffsetBadge = CGSize(width: 0, height: 0)
badge.shadowRadiusBadge = 1.0
badge.shadowColorBadge = UIColor.black
// No shadow
badge.shadowOpacityBadge = 0
// Border width and color
badge.borderWidth = 5.0
badge.borderColor = UIColor.magenta
// Customize the badge corner radius.
// -1 if unspecified. When unspecified, the corner is fully rounded. Default: -1.
badge.cornerRadius = 10
Also. If you don't want to use pods, here is the full and ready to use class It also includes functions I have created:
import UIKit
/**
Badge view control for iOS and tvOS.
Project home: https://github.com/marketplacer/swift-badge
*/
#IBDesignable public class BadgeSwift: UILabel {
/// Background color of the badge
#IBInspectable public var badgeColor = Colors.red {
didSet {
setNeedsDisplay()
}
}
/// Width of the badge border
#IBInspectable public var borderWidth: CGFloat = 0 {
didSet {
invalidateIntrinsicContentSize()
}
}
/// Color of the bardge border
#IBInspectable public var borderColor = Colors.white {
didSet {
invalidateIntrinsicContentSize()
}
}
/// Badge insets that describe the margin between text and the edge of the badge.
#IBInspectable public var insets: CGSize = CGSize(width: 5, height: 2) {
didSet {
invalidateIntrinsicContentSize()
}
}
// MARK: Badge shadow
// --------------------------
/// Opacity of the badge shadow
#IBInspectable public var shadowOpacityBadge: CGFloat = 0.5 {
didSet {
layer.shadowOpacity = Float(shadowOpacityBadge)
setNeedsDisplay()
}
}
/// Size of the badge shadow
#IBInspectable public var shadowRadiusBadge: CGFloat = 0.5 {
didSet {
layer.shadowRadius = shadowRadiusBadge
setNeedsDisplay()
}
}
/// Color of the badge shadow
#IBInspectable public var shadowColorBadge = Colors.black {
didSet {
layer.shadowColor = shadowColorBadge.cgColor
setNeedsDisplay()
}
}
/// Offset of the badge shadow
#IBInspectable public var shadowOffsetBadge: CGSize = CGSize(width: 0, height: 0) {
didSet {
layer.shadowOffset = shadowOffsetBadge
setNeedsDisplay()
}
}
/// Initialize the badge view
convenience public init() {
self.init(frame: CGRect())
}
/// Initialize the badge view
override public init(frame: CGRect) {
super.init(frame: frame)
setup()
}
/// Initialize the badge view
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
/// Add custom insets around the text
override public func textRect(forBounds bounds: CGRect, limitedToNumberOfLines numberOfLines: Int) -> CGRect {
let rect = super.textRect(forBounds: bounds, limitedToNumberOfLines: numberOfLines)
var insetsWithBorder = actualInsetsWithBorder()
let rectWithDefaultInsets = rect.insetBy(dx: -insetsWithBorder.width, dy: -insetsWithBorder.height)
// If width is less than height
// Adjust the width insets to make it look round
if rectWithDefaultInsets.width < rectWithDefaultInsets.height {
insetsWithBorder.width = (rectWithDefaultInsets.height - rect.width) / 2
}
let result = rect.insetBy(dx: -insetsWithBorder.width, dy: -insetsWithBorder.height)
return result
}
/// Draws the label with insets
override public func drawText(in rect: CGRect) {
layer.cornerRadius = rect.height / 2
let insetsWithBorder = actualInsetsWithBorder()
let insets = UIEdgeInsets(
top: insetsWithBorder.height,
left: insetsWithBorder.width,
bottom: insetsWithBorder.height,
right: insetsWithBorder.width)
let rectWithoutInsets = UIEdgeInsetsInsetRect(rect, insets)
super.drawText(in: rectWithoutInsets)
}
/// Draw the background of the badge
override public func draw(_ rect: CGRect) {
let rectInset = rect.insetBy(dx: borderWidth/2, dy: borderWidth/2)
let path = UIBezierPath(roundedRect: rectInset, cornerRadius: rect.height/2)
badgeColor.setFill()
path.fill()
if borderWidth > 0 {
borderColor.setStroke()
path.lineWidth = borderWidth
path.stroke()
}
super.draw(rect)
}
private func setup() {
textAlignment = NSTextAlignment.center
clipsToBounds = false // Allows shadow to spread beyond the bounds of the badge
}
/// Size of the insets plus the border
private func actualInsetsWithBorder() -> CGSize {
return CGSize(
width: insets.width + borderWidth,
height: insets.height + borderWidth
)
}
/// Draw the stars in interface builder
#available(iOS 8.0, *)
override public func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
setup()
setNeedsDisplay()
}
}
func createBadge(_ who: BadgeSwift, _ view: UIView, _ value: String) {
if !view.subviews.contains(who) {
view.addSubview(who)
}
configureBadge(who, view, value)
positionBadge(who, view)
}
func removeBadge(_ who: BadgeSwift, _ view: UIView) {
if view.subviews.contains(who) {
who.removeFromSuperview()
}
}
func configureBadge(_ badge: BadgeSwift, _ view: UIView, _ value: String) {
badge.text = value
badge.insets = CGSize(width: 2, height: 2)
badge.font = UIFont.boldSystemFont(ofSize: 12)
badge.textColor = Colors.white
badge.badgeColor = Colors.badgeRed
}
func positionBadge(_ badge: UIView, _ view: UIView) {
badge.translatesAutoresizingMaskIntoConstraints = false
var constraints = [NSLayoutConstraint]()
constraints.append(NSLayoutConstraint(
item: badge,
attribute: NSLayoutAttribute.centerY,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.top,
multiplier: 1, constant: 5)
)
constraints.append(NSLayoutConstraint(
item: badge,
attribute: NSLayoutAttribute.centerX,
relatedBy: NSLayoutRelation.equal,
toItem: view,
attribute: NSLayoutAttribute.right,
multiplier: 1, constant: -5)
)
view.addConstraints(constraints)
}
func calculateCount(_ items: [UITabBarItem]) -> String {
var countInt = 0
for i in items {
if let countString = i.badgeValue {
countInt = countInt + Int(countString)!
}
}
return String(countInt)
}
For your purpose to create a Badge inside a UITableViewCell, you could use:
let badge = BadgeSwift()
createBadge(badge, MyCell, "10")
That would give you a Badge of 10.

Scala Pickling doesn't seem to work with Point2D.Double

I'm working on a Scala program that uses the Scala Pickling library to serialize and deserialize a Map object that contains a String and a Point2D.Double object from the java.awt.geom package.
Here's the relevant logic:
contents +=
new Button("Save Config") {
reactions += {
case ButtonClicked(_) => {
var m: Map[String, Point2D.Double] = Map()
nodeFields.foreach(x => {
m += (x._1 -> new Point2D.Double(x._2._1.text.toDouble, x._2._2.text.toDouble))
})
val pkl = m.pickle
fc.showSaveDialog(null)
val outputFile = fc.selectedFile
val writer = new PrintWriter(outputFile)
writer.write(pkl.value)
writer.close()
Dialog.showMessage(null, "Success!")
}
}
}
If you need to see more, here's the commit with the offending logic
As it stands, the JSON formatted string output from pkl.value is a working serialized Map[String, Point2D.Double], except that the values of Point2D.Double are dropped!
Here's a snippet of the output:
{
"$type": "scala.collection.mutable.Map[java.lang.String,java.awt.geom.Point2D.Double]",
"elems": [
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "BOTTOMLANE\r",
"_2": {
}
},
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "UPPERLANESECOND_0\r",
"_2": {
}
},
{
"$type": "scala.Tuple2[java.lang.String,java.awt.geom.Point2D.Double]",
"_1": "upperSecondTower_1",
"_2": {
}
},
...
]
}
What can I do to fix this?
scala-pickling can not directly pickle/unpickle Point2D.Double because it has no public fields (the x and y values are accessible through the getX and getY getters).
A possible Pickler / Unpickler for Point2D.Double would be :
object Point2DPickler {
import scala.pickling._
import scala.pickling.Defaults._
import java.awt.geom.Point2D
type DoublePoint = java.awt.geom.Point2D.Double
implicit object Point2DDoublePickle extends Pickler[DoublePoint] with Unpickler[DoublePoint] {
private val doubleUnpickler = implicitly[Unpickler[Double]]
override def tag = FastTypeTag[java.awt.geom.Point2D.Double]
override def pickle(point: DoublePoint, builder: PBuilder) = {
builder.beginEntry(point)
builder.putField("x",
b => b.hintTag(FastTypeTag.Double).beginEntry(point.getX).endEntry()
)
builder.putField("y",
b => b.hintTag(FastTypeTag.Double).beginEntry(point.getY).endEntry()
)
builder.endEntry()
}
override def unpickle(tag: String, reader: PReader): DoublePoint = {
val x = doubleUnpickler.unpickleEntry(reader.readField("x")).asInstanceOf[Double]
val y = doubleUnpickler.unpickleEntry(reader.readField("y")).asInstanceOf[Double]
new Point2D.Double(x, y)
}
}
}
Which could be used as :
import scala.pickling.Defaults._
import scala.pickling.json._
import java.awt.geom.Point2D
import Point2DPickler._
val dpoint = new Point2D.Double(1d, 2d)
scala> val json = dpoint.pickle
json: pickling.json.pickleFormat.PickleType =
JSONPickle({
"$type": "java.awt.geom.Point2D.Double",
"x": {
"$type": "scala.Double",
"value": 1.0
},
"y": {
"$type": "scala.Double",
"value": 2.0
}
})
scala> val dpoint2 = json.value.unpickle[java.awt.geom.Point2D.Double]
dpoint2: java.awt.geom.Point2D.Double = Point2D.Double[1.0, 2.0]

Changing value in textfield with groovy and SwingBuilder

I want to put the value of a variable (==i) in a textfield, so that its value is shown in the textfield, i.e., changing from 1 to 10.
def sb = new SwingBuilder()
def th = Thread.start {
for(i in 1..10) {
sleep 2000
}
}
def Pan = sb.panel(layout: new BorderLayout()) {
sb.panel(constraints: BorderLayout.NORTH){
gridLayout(cols: 2, rows: 3)
textField id:'tf', text: ?
}
}
You can do that with the doOutside method of SwingBuilder, which allows to run a closure outside the EDT. The code below does what you are trying to do (with a table layout instead of a grid layout).
import groovy.swing.SwingBuilder
import static javax.swing.JFrame.EXIT_ON_CLOSE
import java.awt.*
def swingBuilder = new SwingBuilder()
swingBuilder.edt {
def message
def setMessage = { String s -> message.setText(s) }
frame(title: 'Example', size: [200, 150], show: true, locationRelativeTo: null, defaultCloseOperation: EXIT_ON_CLOSE) {
borderLayout(vgap: 5)
panel(constraints: BorderLayout.CENTER, border: emptyBorder(10)) {
tableLayout(cellpadding: 5) {
tr {
td {
label 'Value' // text property is default, so it is implicit.
}
td {
message = textField(id: 'tf', columns: 5, text: '0')
}
}
}
}
}
doOutside {
for (i in 1..10) {
sleep 1000
edt { setMessage(String.valueOf(i)) }
}
}
}

Scala Swing ListView's Remove / Add Elements Events

With reference to this,
How do I change the contents of a ListView in Scala?
I could change ListView contents by changing listData. However, I couldn't get ListView to publish these events, ListElementsAdded, ListElementsAdded and ListChanged. From the looks of ListView source, it would only adds a listener to a read-only empty model. How do I go about this?
Thanks
Later on, I managed to figure out a way to have ListView published these events., please refer to the code.
Is the right to go about it? Is there a better way to do this? Please advise.
Thanks
** code borrowed and modified **
object ListViewTest extends SimpleSwingApplication
{
lazy val top = new MainFrame
{
title = "ListView Test"
contents = new BoxPanel(Orientation.Vertical)
{
border = Swing.EmptyBorder(2, 2, 2, 2)
val listModel = new DefaultListModel
List("First", "Second", "Third", "Fourth", "Fifth").map(listModel.addElement(_))
val myList = ListBuffer()
val listView = new ListView[String](myList)
{
selection.intervalMode = ListView.IntervalMode.Single
peer.setModel(listModel)
//listData = myList
}
listView.peer.getModel.addListDataListener(new ListDataListener {
def contentsChanged(e: ListDataEvent) { publish(ListChanged(listView)) }
def intervalRemoved(e: ListDataEvent) { publish(ListElementsRemoved(listView, e.getIndex0 to e.getIndex1)) }
def intervalAdded(e: ListDataEvent) { publish(ListElementsAdded(listView, e.getIndex0 to e.getIndex1)) }
})
contents += new ScrollPane(listView)
val label = new Label("No selection")
contents += label
val b = new Button("Remove")
contents += b
listenTo(listView.selection, listView, b)
reactions +=
{
case ListSelectionChanged(list, range, live) =>
label.text = "Selection: " + range
case e: ButtonClicked =>
if (listView.listData.isEmpty)
{
b.enabled = false
}
else
{
listView.peer.getModel.asInstanceOf[DefaultListModel].remove(listView.selection.anchorIndex)
}
case ListElementsRemoved(source, range) =>
println("Element at " + (range.start + 1) + " is removed.")
}
}
pack
}