浮点变量在没有明确赋值的情况下被改变。

huangapple 未分类评论52阅读模式
英文:

float variable beign changed without beign explicitely atributted

问题

我甚至不知道如何描述我现在遇到的这种奇怪行为,但问题是:

我有一个名为 Player.java 的类,其中有一个私有的浮点数 life,非常基础。
这个浮点数有它自己的设置器/获取器,没有其他方式可以在不使用获取器/设置器的情况下检索/赋值这个变量。

另外,我在每个获取器/设置器中都放了一个 println,以便我可以得到这个变量被检索时的反馈,以及何时被赋值,我在我的控制台上看到了这个:

我的控制台

我不认为堆栈跟踪在任何情况下都有用,但如果你想要的话,我可以粘贴堆栈跟踪后面的代码。

无论如何,如果你还没有注意到,这里有一个检索 life = 61,后面是一个检索 life = 70,完全没有将这个变量回归到 70 的任何赋值。

另外,我不知道这是否有用,但这是打印 "1 damaged 0, broadcasting to clients - Sent" 的代码:

它总结如下:

  • 减少玩家生命值
  • 如果玩家死亡,标记为死亡并进行其他小的效果处理
  • 发送事件到 Google Analytics
  • 在所有这些操作之后,如果游戏是服务器,则向所有客户端广播伤害事件
  1. public void takeDamage(float amount, Player owner, boolean showBlood, boolean local) {
  2. if (local && KambojaMain.getInstance().multiplayerConnection && !KambojaMain.getInstance().isServer) return;
  3. if (imunity <= 0) {
  4. //new Exception().printStackTrace();
  5. setLife(getLife() - amount * def);
  6. if (owner != null) {
  7. owner.score += amount * def;
  8. }
  9. if (showBlood)
  10. state.showBlood(body.getWorldCenter());
  11. System.out.println(" - DAMAGE DETECTED from " + owner.getId() + " to " + getId() + " with value " + amount + ", it was a local? " + local + ", and show blood is: " + showBlood);
  12. System.out.println("target life is now at " + getLife());
  13. hitTimer = 1f;
  14. if (getLife() <= 0) {
  15. if (!isDead()) {
  16. deaths++;
  17. if (owner != null) {
  18. owner.kills++;
  19. owner.ghosts.add(new Ghost(getId(), getPosition()));
  20. owner.score += 100;
  21. }
  22. setDead(true);
  23. body.getFixtureList().get(0).setSensor(true);
  24. getState().showSkull(body.getWorldCenter(), getAngle());
  25. String playerType = "controller";
  26. if (isKeyboard()) {
  27. playerType = "keyboard";
  28. }
  29. if (this instanceof BetterBot) {
  30. playerType = "bot";
  31. }
  32. HashMap<String, String> customs = new HashMap<String, String>();
  33. customs.put("cd1", KambojaMain.getMapName());
  34. customs.put("cd3", getWeapon().getClass().getSimpleName());
  35. customs.put("cd4", "player_" + playerType);
  36. String ow = "Suicide";
  37. if (owner != null)
  38. ow = owner.getWeapon().getClass().getSimpleName();
  39. KambojaMain.event("game", "player_kill", ow, customs);
  40. }
  41. }
  42. if (gruntTimer < 0) {
  43. if (GameState.SFX)
  44. grunt[(int) (Math.random() * 5)].play();
  45. gruntTimer = 0.5f;
  46. }
  47. if (KambojaMain.getInstance().multiplayerConnection && KambojaMain.getInstance().isServer) {
  48. KambojaPacket kp = new KambojaPacket(PacketType.PLAYER_DAMAGE);
  49. PlayerDamage pd = new PlayerDamage();
  50. pd.damage = amount;
  51. pd.showBlood = showBlood;
  52. pd.owner = owner.getId();
  53. pd.target = getId();
  54. kp.data = pd;
  55. System.out.print(pd.owner + " damaged " + pd.target + ", broadcasting to clients - ");
  56. KambojaMain.getInstance().broadcast(kp, Protocol.TCP);
  57. System.out.println("Sent");
  58. }
  59. }
  60. }

注意:我正在使用多线程环境,因为这是一个局域网多人游戏,这个变量可以在不同于主线程的其他线程中检索。

我已经尝试过使用 volatile 关键字、原子类(没有 AtomicFloat,尝试使用 AtomicInt 实现它作为位数据),但这些都不能防止这种情况发生,我不知道这种行为是什么以及是什么原因导致的。

有人能帮帮我吗?我不知道还能搜索什么。

英文:

I don't event know how to describe this weird behaviour i'm dealing with right now, but the thing is:

I have a class Player.java that has a private float life, pretty basic.
this float has its setter / getter and there is NO other way of retrieving / attributing this variable without using the getter / setter.

also, i have put a println in each, so i can have a feedback of when this variable is being retrieved, and when is beign attributed, and i get THIS on my console:

my console

i don't think the stack trace is usefull in any way, but if you want to, i can paste the code behind the stack trace too

anyway, if you haven't notice, there is a retrieve of life = 61, FOLLOWED by a retriving of life = 70, with NO attribution WHATSOEVER of this variable back to 70.

also, i dont know if this is useful, but here is the code that prints the "1 damaged 0, broadcasting to clients - Sent":

it resume in:

  • decreases the player life
  • if it has died, mark as dead and do other little effect things
  • send event to google analytics
  • after all that, if the game is a server, broadcast the damage event to all clients
  1. public void takeDamage(float amount, Player owner, boolean showBlood, boolean local){
  2. if(local &amp;&amp; KambojaMain.getInstance().multiplayerConnection &amp;&amp; !KambojaMain.getInstance().isServer) return;
  3. if(imunity &lt;= 0){
  4. //new Exception().printStackTrace();
  5. setLife(getLife() - amount * def);
  6. if(owner != null) {
  7. owner.score += amount*def;
  8. }
  9. if(showBlood)
  10. state.showBlood(body.getWorldCenter());
  11. System.out.println(&quot; - DAMAGE DETECTED from &quot; + owner.getId() + &quot; to &quot; + getId() + &quot; with value &quot; + amount + &quot;, it was a local? &quot; + local + &quot;, and show blood is: &quot; + showBlood);
  12. System.out.println(&quot;target life is now at &quot; + getLife());
  13. hitTimer = 1f;
  14. if(getLife() &lt;= 0){
  15. if(!isDead()){
  16. deaths++;
  17. if(owner != null){
  18. owner.kills ++;
  19. owner.ghosts.add(new Ghost(getId(), getPosition()));
  20. owner.score += 100;
  21. }
  22. setDead(true);
  23. body.getFixtureList().get(0).setSensor(true);
  24. getState().showSkull(body.getWorldCenter(), getAngle());
  25. String playerType = &quot;controller&quot;;
  26. if(isKeyboard()) {
  27. playerType = &quot;keyboard&quot;;
  28. }
  29. if(this instanceof BetterBot) {
  30. playerType = &quot;bot&quot;;
  31. }
  32. HashMap&lt;String, String&gt; customs = new HashMap&lt;String, String&gt;();
  33. customs.put(&quot;cd1&quot;, KambojaMain.getMapName());
  34. customs.put(&quot;cd3&quot;, getWeapon().getClass().getSimpleName());
  35. customs.put(&quot;cd4&quot;, &quot;player_&quot; + playerType);
  36. String ow = &quot;Suicide&quot;;
  37. if(owner != null)
  38. ow = owner.getWeapon().getClass().getSimpleName();
  39. KambojaMain.event(&quot;game&quot;, &quot;player_kill&quot;, ow, customs);
  40. }
  41. }
  42. if(gruntTimer &lt; 0){
  43. if(GameState.SFX)
  44. grunt[(int)(Math.random()*5)].play();
  45. gruntTimer = 0.5f;
  46. }
  47. if(KambojaMain.getInstance().multiplayerConnection &amp;&amp; KambojaMain.getInstance().isServer) {
  48. KambojaPacket kp = new KambojaPacket(PacketType.PLAYER_DAMAGE);
  49. PlayerDamage pd = new PlayerDamage();
  50. pd.damage = amount;
  51. pd.showBlood = showBlood;
  52. pd.owner = owner.getId();
  53. pd.target = getId();
  54. kp.data = pd;
  55. System.out.print(pd.owner + &quot; damaged &quot; + pd.target + &quot;, broadcasting to clients - &quot;);
  56. KambojaMain.getInstance().broadcast(kp, Protocol.TCP);
  57. System.out.println(&quot;Sent&quot;);
  58. }
  59. }
  60. }

note: i AM using multi threading environment because this is a lan multiplayer game, and this variable can be retrieved in other threads different from the main thread.

I have searched about the volatile keyword, Atomic classes (AtomicFloat dont exist, and the implementation of it using AtomicInt as a bit data also was used), but none of this could prevent this from happening and i have NO idea of what is this behaviour and what is causing it

can someone please help me? i don't know what to search anymore

答案1

得分: 0

尝试将你的方法设为synchronized(这将确保只有一个线程可以在类的实例上运行此方法)。

  1. public synchronized void takeDamage(.... // 与之前相同的代码

查看这篇帖子,其中有一个类似的问题,提供了有关以原子方式运行代码块的更多信息。

英文:

Try making your method synchronized (this would make sure only one thread can be running this method, on an instance of your class).

  1. public synchronized void takeDamage(.... // same as before

Check out this post, it has a similar question with more info about running blocks of code atomically.

huangapple
  • 本文由 发表于 2020年4月5日 08:30:33
  • 转载请务必保留本文链接:https://java.coder-hub.com/61036591.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定